/*Main file for any SERVANT function*/

#include "projectHeader.h"

/*void sigchildHandling(int signalReceived) 
{    
	//cout<<"Interrupt handling function..."<<endl;
	//serverShutdown=1;
	pthread_kill(tid,SIGSEGV);
}  
*/


int main(int argc,char *argv[])
{


	//Handle signal Handling here..

//======================Parse the command line=============//
/*
sigset_t x;
sigemptyset (&x);
sigaddset(&x, SIGPIPE);
sigprocmask(SIG_BLOCK, &x, NULL);


sig_action.sa_handler = sigUsrHandling;
sigaction(SIGUSR, &sig_action, NULL);
pthread_sigmask(SIG_UNBLOCK, &sig, NULL);
*/
signal (SIGALRM, handleAutoShutdown);

	int ac;
	ac=argc;
	//char **av=argv;
	configFileName=NULL;
	signal(SIGPIPE,SIG_IGN);
	if(argc<2 || argc>3)
	{
		printf("ERROR:\t Incorrect number of arguments.\n");
		exit(0);

	}
	//printf("%d \n",argc);
	argc--;
	argv++;
	//printf("%d \n",argc);
	for(; argc > 0;argc--, argv++)
	{
		if (*argv[0] == '-')
		{
			if(strcmp(*argv,"-reset")==0)
			{
			
			//printf("Reset Option Detected\n");
			resetOptionDetected=true;
			//printf("%d \n",argc);
				if(argc==1)
				{
					printf("ERROR: configFileName not specified.\n");
					exit(0);
				}
			}
			else
			{
				printf("ERROR:\t Invalid Option detected.\n");
				exit(0);
			}
		}
		else
		{
			//printf("%d \n",argc);
			configFileName=argv[0];
			//printf("configFileName passed is %s\n",configFileName);
		}
	
	}
	//printf("%d ends \n",argc);


//==================Command Parsing Complete===================//


//=========Parse the init File passed from command line==========//





while(1)
{






		inittime=time(NULL);
		gethostname(myHostName, sizeof(myHostName));
		//printf("\n\n\nMYHostNAme is %s\n",myHostName);

		//strcpy(logFileName,"servant.log");
		initParse();
		noCheck=1;
		pthread_mutex_init (&indexMutex,NULL);
		//load all the index structures.
		retrieveIndexStructure();


		//delete all files if reset flag is specified.
		if(resetOptionDetected)
		{
			//delete log file, kwrd_index, name_index, sha1_index, *.meta, *.data
			//char initNeighbourListFile[512];
			//memset(initNeighbourListFile,'\0',512);
			//printf("HomeDir: %s\n",homeDir);
			//memcpy(initNeighbourListFile,homeDir,strlen(homeDir));
			//strcat(initNeighbourListFile,"/files/init_neighbor_list");
			//printf("\nIN RESET SECTION : InitNeighbourList File path is: %s\n",initNeighbourListFile);
			//remove(initNeighbourListFile);
			
			char logFile[512];
			memset(logFile,'\0',512);
			memcpy(logFile,homeDir,strlen(homeDir));
			strcat(logFile,"/");
			//printf("HomeDir: %s\n",homeDir);
			if(logFileName!=NULL)
				memcpy(&logFile[strlen(homeDir)+1],logFileName,strlen(logFileName));
			else
				memcpy(&logFile[strlen(homeDir)+1],"servant.log",strlen("servant.log"));

		//	printf("\nIN RESET SECTION : status log File is: %s\n",logFile);
			remove(logFile);
			
			
			for(int k=1;k<numFileNameCounter;k++)
			{
				char nameD[512];
				char nameM[512];
				memset(&nameD[0],'\0',512);
				memset(&nameM[0],'\0',512);
				memcpy(nameD,homeDir,strlen(homeDir));
				memcpy(nameM,homeDir,strlen(homeDir));
				strcat(nameD,"/files");
				strcat(nameM,"/files");	
					
					char appendDFileName[256];
					char appendMFileName[256];
					memset(&appendMFileName[0],'\0',256);
					memset(&appendDFileName[0],'\0',256);
					
					sprintf(appendDFileName, "/%d.data", k);
					sprintf(appendMFileName, "/%d.meta", k);

					strcat(nameD,appendDFileName);
					strcat(nameM,appendMFileName);

				bool dfileExist=false;
				struct stat s4;
				if(stat(nameD,&s4) == -1){
					printf("Invalid Path name: %s\n",nameD);

					dfileExist=false;
				}
				if (S_ISREG(s4.st_mode))
				{
				  dfileExist=true;
				}
							
				if(dfileExist)
				{
					remove(nameD);
				}
				bool mfileExist=false;
				struct stat s5;
				if(stat(nameM,&s5) == -1){
					printf("Invalid Path name%s\n",nameM);
					mfileExist=false;
				}
				if (S_ISREG(s4.st_mode))
				{
				  mfileExist=true;
				}
							
				if(mfileExist)
				{
					remove(nameM);
				}

			}


			numFileNameCounter=1;
			cacheSizeInBytes=cacheSize*1024;
			remainingCacheSizeInBytes=cacheSize*1024;
			char kwrdIndex[512];
			memset(kwrdIndex,'\0',512);
			memcpy(kwrdIndex,homeDir,strlen(homeDir));
			strcat(kwrdIndex,"/kwrd_index");
			remove(kwrdIndex);

			char nameIndex[512];
			memset(nameIndex,'\0',512);
			memcpy(nameIndex,homeDir,strlen(homeDir));
			strcat(nameIndex,"/name_index");
			remove(nameIndex);

			char sha1Index[512];
			memset(sha1Index,'\0',512);
			memcpy(sha1Index,homeDir,strlen(homeDir));
			strcat(sha1Index,"/sha1_index");
			remove(sha1Index);
			
			char nameNumIndex[512];
			memset(nameNumIndex,'\0',512);
			memcpy(nameNumIndex,homeDir,strlen(homeDir));
			strcat(nameNumIndex,"/nameNum_index");
			remove(nameNumIndex);
			
			char numIndex[512];
			memset(numIndex,'\0',512);
			memcpy(numIndex,homeDir,strlen(homeDir));
			strcat(numIndex,"/num_index");
			remove(numIndex);

			

			//remove(sha1Index);
			indexFileMetaInfoList.clear();
			indexBitVectoreList.clear();
			indexSHA1Map.clear();
			numToFileIdMap.clear();
			resetOptionDetected = false;
		}

		alarm (autoShutDown);
		//alarm(1000);
		// myHostPortInfo=hostPort(myHostName,itoa(port,buf,10));


//		list<hostPort>::iterator it;
//		for (it=beaconList.begin(); it!=beaconList.end(); it++)
//		{
//			printf("Host is: %s Port is %s\n",(*it).hostName,(*it).portNum);	
//		}
		//Generate NodeInstanceId
		
		char nodeInstanceId1[512];
		sprintf(nodeInstanceId1,"%s_%d",myHostName,port);
		//printf("NodeID is %s\n",nodeInstanceId1);
		strcat(nodeInstanceId1,"_");
		//printf("NodeID is %s\n",nodeInstanceId1);
		sprintf(nodeInstanceId1,"%s%d",nodeInstanceId1,(int)inittime);
		//printf("NodeID is %s\n",nodeInstanceId1);
		//nodeInstanceId=nodeInstanceId1;
		memcpy(&nodeInstanceId[0],&nodeInstanceId1[0],strlen(nodeInstanceId1));
//		printf("NodeID is %s\n",nodeInstanceId);
		
		char logFileNameOpen[512];
		//strcpy(logFileNameOpen,homeDir);
		//strcat(logFileNameOpen,"/servant.log");
		
		
	
		if(logFileName==NULL)
		{
			strcpy(logFileNameOpen,homeDir);
			strcat(logFileNameOpen,"/servant.log");
		
			
		}
		else
		{
			strcpy(logFileNameOpen,homeDir);
			strcat(logFileNameOpen,"/");
			strcat(logFileNameOpen,logFileName);
		
		}
		if(!logAlreadyOpen)
		{
			logFilePtr=fopen(logFileNameOpen,"w");
			logAlreadyOpen=true;
		}
		
		if(logFilePtr==NULL)
		{
			printf("ERROR OPENING LOG FILE.\n");
			exit(1);
		}


		
	//	memset(newNumDataFile, '\0', 256);
	/*	char newNumDataFile[256];
		memcpy(newNumDataFile,homeDir,strlen(homeDir));
		strcat(newNumDataFile,"/temp");
		mkdir(newNumDataFile,S_IRWXU | S_IRWXG | S_IRWXO);
*/


		//Generate UOid for the Node here===========//
/*
		unsigned char *buff1;
		char* msg = (char*)"msg";
		buff1 = GetUOID(nodeInstanceId, msg,buf,sizeof(buf));
		//printf("\nBuffer is  : %s and length is : %d\n",buf,strlen((char*)buf));
		printUOID(buf);
*/

		//=====Will check if I am the beacon node or not=========///
		pthread_mutex_init(&connectedNodeListMutex,NULL);
		pthread_mutex_init(&joinTimeOutBoolMutex , NULL);
		pthread_mutex_init(&printMutex , NULL);
		pthread_mutex_init(&wQBitsetMutex,NULL);
		pthread_mutex_init(&sockIndexMapMutex,NULL);
		pthread_mutex_init(&logFileMutex,NULL);
		pthread_mutex_init(&eventQueueMutex,NULL);
		pthread_cond_init(&eventQueueCV,NULL);
		pthread_mutex_init(&keepAliveMapMutex,NULL);
		pthread_mutex_init(&checkTimeoutMutex,NULL);
		pthread_cond_init(&checkTimeoutCV,NULL);
		pthread_mutex_init(&cntrlCFlagMutex,NULL);
		pthread_mutex_init(&UOIDMsgLifeTimeMapMutex,NULL);
		pthread_mutex_init (&indexMutex,NULL);
		pthread_mutex_init (&tempfileindexlock,NULL);
		pthread_mutex_init(&statusFileWriteLock,NULL);
		for(int j=0;j<512;j++)
		{
			pthread_mutex_init(&wrtieQMutex[j],NULL);
			pthread_cond_init(&wrtieQCV[j],NULL);
		
		}
		pthread_create(&userTermialThread,NULL,userTerminal,NULL);
		if(iAmBeacon)
		{
			//Code for Beacon node here.

			//Create all the threads needed and join them here..
			/*
			1)keepalivemsg detection thread
			2)keepalivetimeout  detection thread
			3)eventDispatcher thread
			4)beaconConnect thread
			5)beaconAccept thread
			*/
//			printf("Will open pThreads for beaconConnect now..\n\n");
			// Create the connectThread for all beacon nodes in list....
			pthread_create(&eventDispatcherThreadId, NULL,eventDispatcher,NULL);
			pthread_create(&msgLifeTimer, NULL,msgLifeTimeTimer,NULL);
			//pthread_create(&userTermialThread,NULL,userTerminal,NULL);

			int lenghtOfList = (int)beaconList.size();
			connectingThread=(pthread_t *)(malloc(lenghtOfList*sizeof(pthread_t)));
			int i=0;

			
	
			pthread_create(&acceptingThread, NULL,beaconAccept,NULL);
			
			list<hostPort>::iterator it;
			for (it=beaconList.begin(); it!=beaconList.end(); it++,i++)
			{
				pthread_create(&connectingThread[i], NULL,beaconConnect,(void *)&(*it));
			}
			pthread_create(&keepAlive,NULL,keepAliveMsg,NULL);
			pthread_create(&keepAliveTimeout,NULL,keepAliveTimeOutThread,NULL);
	//		printf("After Create\n\n");


			//join all threads here...
			pthread_join(keepAlive,NULL);
			pthread_join(keepAliveTimeout,NULL);
			pthread_join(eventDispatcherThreadId,NULL);
			pthread_join(msgLifeTimer,NULL);
			pthread_join(acceptingThread,NULL);
			for (it=beaconList.begin(); it!=beaconList.end(); it++,i++)
			{
				pthread_join(connectingThread[i],NULL);
			}

			pthread_join(userTermialThread,NULL);
//			printf("After Join\n\n");
		}
		else
		{
			/*Code for Non-Beacon node here.
			- Try to open the file init_neighbor_list in Homedir of the node
			-If 
			File opened succesfully
					=Create threads for keepalive, keepalivetimeout, eventdispatcher adn terminalinput
					=Create nonBeaconAccept thread .
					=Make InitNeighbours number of threads of nonBeaconConnect type.
					=IF 
						number of connection setup are less than MinNeighbours the kill all created pthread, delete the init_neighbor_list file and do SOFT RESTART.
					=ELSE
						Join all the threads created.
			-ELSE
					=Create JoinTimeOut thread.
					=Create a nonBeaconConnect to make temp connection with a beacon.
					=Join the pthreads.
					=Then proceed to SOFT RESTART.



			*/
			
//			printf("I am a Non Beacon Node\n");
			
			char initNeighbourListFile[512];
			memset(initNeighbourListFile,'\0',512);
//			printf("HomeDir: %s\n",homeDir);
			memcpy(initNeighbourListFile,homeDir,strlen(homeDir));
			strcat(initNeighbourListFile,"/init_neighbor_list");
//			printf("InitNeighbourList File path is: %s\n",initNeighbourListFile);

			//http://cboard.cprogramming.com/linux-programming/88539-delete-file-linux.html
			//remove(initNeighbourListFile);
			initNeighbourListFP=fopen(initNeighbourListFile,"r");
			if (initNeighbourListFP!=NULL)
			{
				fileOpenSucces=true;	
				//printf("init_neighbor_list.ini opened succesfully \n");
			}
			else
			{
				//printf("ERROR: init_neighbor_list.ini cannot be opened succesfully \n");
				fileOpenSucces=false;
			
			}
			
			if(fileOpenSucces)
			{
				//File Opened Successfully
				//File Opened Successfully
				//File Opened Successfully
				/*=Create threads for keepalive, keepalivetimeout, eventdispatcher adn terminalinput
					=Create nonBeaconAccept thread .
					=Make InitNeighbours number of threads of nonBeaconConnect type.
					=IF 
						number of connection setup are less than MinNeighbours the kill all created pthread, delete the init_neighbor_list file and do SOFT RESTART.
					=ELSE
						Join all the threads created.
				*/
				//beaconList.clear();
				char fileHostPortString [512];
				memset(fileHostPortString,'\0',512);
				while( fgets(fileHostPortString,sizeof(fileHostPortString),initNeighbourListFP))
				{
					//fscanf (initNeighbourListFP, "%s", fileHostPortString);
					remLeadingSpaces(fileHostPortString);
					char* tempStore=removeTrailingWhiteSpace(fileHostPortString);
					memcpy(&fileHostPortString[0],tempStore,strlen(tempStore));
//					printf("\nFile read string is : %s\n",fileHostPortString);
					//Store host and port in list beaconList. 

					//char *temp=NULL;
					//temp=strtok(fileReadDataBufModified,"=");
					//printf("FILE OPEN SUCCESS --> Temp:  %s\n",temp);
					char *key1=strtok(fileHostPortString,":");
//					printf("FILE OPEN SUCCESS --> Key: %s and strlen(key1) = %d\n",key1,strlen(key1));
					char *value=strtok(NULL,":");
//					printf("FILE OPEN SUCCESS --> value:  %s\n",value);
					//int portNum= atoi(value);
					//printf("retry: %d\n",retry);
					//retryFlag=true;
					hostPort p(key1,value);
					nonBeaconList.push_back(p);
				}
//				printf("\nBeacon list size is : %d\n",nonBeaconList.size());
				//create multiple threads.
				//accept, connect threads, dispatcher
				int lenghtOfList = (int)nonBeaconList.size();
				connectingThread=(pthread_t *)(malloc(lenghtOfList*sizeof(pthread_t)));
//				list<hostPort>::iterator it1;
				//int i=0;
//				for (it1=nonBeaconList.begin(); it1!=nonBeaconList.end(); it1++)
//				{
//					printf("INSIDE NONBEACON FILE FOUND ::: Host is: %s Port is %s\n",(*it1).hostName,(*it1).portNum);	
//				}
				//pthread_create(&eventDispatcherThreadId, NULL,eventDispatcher,NULL);
				//pthread_create(&acceptingThread, NULL,beaconAccept,NULL);
				list<hostPort>::iterator it2;
				int k=0;
				for (it2=nonBeaconList.begin(); it2!=nonBeaconList.end(); it2++,k++)
				{
					pthread_create(&connectingThread[k], NULL,nonBeaconConnect,(void *)&(*it2));
				}
				//pthread_join(eventDispatcherThreadId,NULL);
				//pthread_join(acceptingThread,NULL);
				pthread_create(&keepAlive,NULL,keepAliveMsg,NULL);
				pthread_create(&keepAliveTimeout,NULL,keepAliveTimeOutThread,NULL);
				//pthread_cancel(userTermialThread);
				
				//pthread_create(&userTermialThread,NULL,userTerminal,NULL);
				pthread_create(&eventDispatcherThreadId, NULL,eventDispatcher,NULL);
				pthread_create(&msgLifeTimer,NULL,msgLifeTimeTimer,NULL);

				sleep(keepAliveTimeOut+1);
				pthread_create(&acceptingThread, NULL,nonBeaconAccept,NULL);           
				pthread_mutex_lock(&sockIndexMapMutex);

				if((int)sockFDToQIndexMap.size()<minNeighbour)
				{
					/*fclose(initNeighbourListFP);
					remove(initNeighbourListFile);
					
					//delelte init_neighbor_list file.
					int i=0;
					list<hostPort>::iterator it4;
					for (it4=nonBeaconList.begin(); it4!=nonBeaconList.end(); it4++,i++)
					{
						pthread_cancel(connectingThread[i]);
					}
					pthread_cancel(keepAlive);
					pthread_cancel(keepAliveTimeout);
					
					pthread_cancel(userTermialThread);
					pthread_cancel(eventDispatcherThreadId);
					pthread_cancel(msgLifeTimer);
					pthread_cancel(acceptingThread);  
					pthread_mutex_unlock(&sockIndexMapMutex);
					// kill connect threads.
					softRestart();
					//soft restart.*/
					initiateUserShutDownSequence();
					
					continue;
									
					
				}
				pthread_mutex_unlock(&sockIndexMapMutex);
				
				//pthread_create(&userTermialThread,NULL,userTerminal,NULL);
				
				

			//	pthread_mutex_lock(&checkTimeoutMutex);
				/*if(checkFlagReceived==false)
				{
						//exit(0);
						//printf("SV_NODE:sitting on waitto check check check timeout timeout\n");
						pthread_mutex_unlock(&checkTimeoutMutex);
						while(1)
						{
							pthread_mutex_lock(&checkTimeoutMutex);
							pthread_cond_wait(&checkTimeoutCV, &checkTimeoutMutex);
							if(broadCastSent ==true)
							{
						//		printf("\nEnter in condition variable...\n");
								pthread_mutex_unlock(&checkTimeoutMutex);
								break;
							}
							pthread_mutex_unlock(&checkTimeoutMutex);
							//else if(cntrlCFlag==true)
							//{
							//	continue;
							//}
						}
						broadCastSent =false;
						//!cntrlCFlag && checkFlagReceived==true
						
//						printf("SV_NODE:check timeout got signal to Restart got signal to Restart  got signal to Restart  from check ");
						pthread_mutex_unlock(&checkTimeoutMutex);
						//checkFlagReceived=true;
						
						//pthread_mutex_unlock(&counter_mutex);
						
						pthread_cancel(checkTimeOut);

//						printf("SVNODE:check timeout_thread killed\n");

						//pthread_cancel(keyboard_thread);

						int m=0;
						list<hostPort>::iterator it4;
						for (it4=nonBeaconList.begin(); it4!=nonBeaconList.end(); it4++,m++)
						{
							pthread_cancel(connectingThread[m]);
						}
						pthread_cancel(eventDispatcherThreadId);
						pthread_cancel(msgLifeTimer);
						pthread_cancel(acceptingThread);        
						pthread_cancel(keepAlive);
						pthread_cancel(keepAliveTimeout);

						//pthread_cancel(userTermialThread);

						fclose(initNeighbourListFP);
						remove(initNeighbourListFile);
						
	
						// kill connect threads.
						softRestart();
						//soft restart.
						
						continue;
					

				}*/
			//	pthread_mutex_unlock(&checkTimeoutMutex);



				int j=0;
				list<hostPort>::iterator it3;
				for (it3=nonBeaconList.begin(); it3!=nonBeaconList.end(); it3++,j++)
				{
					pthread_join(connectingThread[j], NULL);
				}
				pthread_join(eventDispatcherThreadId,NULL);
				pthread_join(acceptingThread,NULL);        
				pthread_join(keepAlive,NULL);
				pthread_join(keepAliveTimeout,NULL);

				pthread_join(userTermialThread,NULL);









			}
			else
			{
				
				//Error in opening init_neighbor_list file..
				
				//Create JoinTimeOut thread.  
//				pthread_create(&nonBeaconJoinTimeOut,NULL,joinTimeOutThread,NULL);
				//Create a nonBeaconConnect to make temp connection with a beacon.       
//				pthread_create(&nonBeaconJoinConnectThread, NULL,nonBeaconJoinConnect,NULL);
				//Join the pthreads.                          
//				pthread_join(nonBeaconJoinTimeOut,NULL);
//				pthread_join(nonBeaconJoinConnectThread,NULL);
				//Then proceed to SOFT RESTART.                                          
//				pthread_cancel(userTermialThread);
				initiateUserShutDownSequence();
				//softRestart();
				continue;
				//printf("After soft restart.\n\n");
			}
			//pthread_join(userTermialThread,NULL);
		}//else for iAmBeacon

}//end of while(1)

//printf("\nEnd of main()..\n");
pthread_exit(NULL);

return 0;
}
